home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1990-1992 by Michael Davidson.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation.
- *
- * This software is provided "as is" without express or implied warranty.
- */
-
- /*
- * file selection menu
- */
- #include <stdio.h>
-
- #include "vg.h"
- #include "kbd.h"
- #include "text.h"
- #include "video.h"
-
- static int FileMenuMode = -1;
- static vmode_t *FileMenuModeInfo = NULL;
-
- extern char *CurrentDirectory;
-
- extern void *alloca(int);
-
- #define CURSOR 1
- #define SELECTED 2
-
- typedef struct row_col
- {
- int row;
- int col;
- } row_col_t;
-
-
- void
- fileMenu(
- list_t *filelist
- )
- {
- int x, y, width, height;
- list_t *f;
- list_t *l;
- list_t **ll;
- list_t ***list_layout;
- unsigned char *p;
-
- int nitems; /* total # of items in list */
- int rows; /* total # of rows in list */
- int cols; /* total # of columns in list */
- int row; /* current row */
- int col; /* current column */
- int col_width; /* width of one column */
- row_col_t first; /* first displayed item in list */
- row_col_t last; /* last item in list */
- row_col_t cursor; /* cursor position in list */
- row_col_t info; /* file info position */
- int info_len; /* file info length */
- char *info_buf;
- int display_rows; /* # of displayable rows */
- int display_cols; /* # of displayable columns */
- extern int nomenu;
- extern int menuwidth;
-
- if (nomenu)
- {
- for (f = filelist; f != NULL; f = f->next)
- f->flags |= 2;
- showFiles(filelist);
- return;
- }
- if (FileMenuMode == -1)
- {
- FileMenuMode = bestDisplayMode(V_TEXT_MODE, menuwidth, 25, 0);
- FileMenuModeInfo= vidModeInfo(FileMenuMode);
- }
- vidSetMode(FileMenuMode);
-
- vidClear(BLUE);
-
- menuBorders(0, 0, FileMenuModeInfo->width, FileMenuModeInfo->height,
- CurrentDirectory, "");
-
- info.row = FileMenuModeInfo->height - 2;
- info.col = 2;
- info_len = FileMenuModeInfo->width - 4;
- info_buf = (char *)alloca(info_len);
-
- /*
- * calculate # of items and maximum length of an item name
- */
- x = 2;
- y = 3;
- width = FileMenuModeInfo->width - 4;
- height = FileMenuModeInfo->height - 6;
-
- col_width = 0;
- nitems = 0;
-
- for (l = filelist; l != NULL; l = l->next)
- {
- int len;
-
- len = strlen(l->name);
- if (len > col_width)
- col_width = len;
- ++nitems;
- }
-
- if (nitems == 0)
- return ;
-
- /*
- * calculate # of rows and colums in list
- */
- /*
- * for now just use a fixed formula for this - later
- * should allow this to be specified
- */
- rows = height;
- cols = (nitems + (rows - 1)) / rows;
-
- /*
- * build a 2-D array of pointers to the list items indexed
- * by column and row number
- */
- p = alloca(cols*sizeof(list_t **) + rows*cols*sizeof(list_t *));
-
- /*
- * set up the column pointers
- */
- list_layout = (list_t ***)p;
- ll = (list_t **) (p + (cols * sizeof(list_t **)));
- for (col = 0; col < cols; col++)
- {
- list_layout[col] = ll;
- ll += rows;
- }
-
- cursor.row = 0;
- cursor.col = 0;
- /*
- * fill in the pointers to the actual list items
- */
- l = filelist;
- for (col = 0; col < cols; col++)
- for (row = 0; row < rows; row++)
- {
- list_layout[col][row] = l;
- if (l != NULL)
- {
- if (l->flags & CURSOR)
- {
- cursor.row = row;
- cursor.col = col;
- }
- l = l->next;
- }
- }
-
- /*
- * calculate # of rows and columns that can be displayed in the window
- */
- display_rows = height;
- display_cols = width / (col_width + 1);
- if (display_cols == 0)
- display_cols = 1;
- col_width = width / display_cols;
- if (display_cols > cols)
- display_cols = cols;
-
- /*
- * first list item to display
- */
- first.row = 0;
- first.col = 0;
- last.col = cols - 1;
- last.row = nitems - (rows * (cols-1)) - 1;
-
- list_layout[cursor.col][cursor.row]->flags |= CURSOR;
-
- for (;;)
- {
- row_col_t old_cursor;
- int cursor_changed;
- int redraw;
-
- /*
- * redraw the the list
- */
- vidClear(BLUE);
-
- menuBorders(0, 0, FileMenuModeInfo->width, FileMenuModeInfo->height,
- CurrentDirectory, "");
-
- for (col = 0; col < display_cols; col++)
- {
- int ix;
- int iy;
- int iw;
-
- ix = x + (col * col_width);
- iw = col_width - 1;
- if (ix + iw > x + width)
- iw = (x + width) - ix;
- for (row = 0, iy = y; row < display_rows; row++, iy++)
- drawListItem(ix, iy, iw,
- list_layout[first.col + col][first.row + row]);
- }
- /*
- * update file info
- */
- memset(info_buf, ' ', info_len);
- fileInfo(list_layout[cursor.col][cursor.row]->name, info_buf, info_len);
- vidPutText(info.col, info.row, info_buf, info_len, LT_CYAN, BLUE);
-
- redraw = 0;
-
- while (! redraw)
- {
- int key;
-
- cursor_changed = 0;
- old_cursor = cursor;
-
- key = kbdGetKey(K_WAIT);
-
- switch (key)
- {
- case K_UP: /* cursor up */
- --cursor.row;
- cursor_changed = 1;
- break;
-
- case ' ': /* select */
- list_layout[cursor.col][cursor.row]->flags ^= SELECTED;
- /* fall through */
- case K_DOWN: /* cursor down */
- ++cursor.row;
- cursor_changed = 1;
- break;
-
- case K_RIGHT: /* cursor right */
- ++cursor.col;
- cursor_changed = 1;
- break;
-
- case K_LEFT: /* cursor right */
- --cursor.col;
- cursor_changed = 1;
- break;
-
- case K_HOME:
- cursor.col = 0;
- cursor.row = 0;
- cursor_changed = 1;
- break;
-
- case K_END:
- cursor = last;
- cursor_changed = 1;
- break;
-
- case K_ENTER:
- for (l = filelist; l != NULL; l = l->next)
- if (l->flags & SELECTED)
- break;
-
- if (l == NULL)
- list_layout[cursor.col][cursor.row]->flags |= SELECTED;
-
- showFiles(filelist);
-
- for (l = filelist; l != NULL; l = l->next)
- l->flags &= ~SELECTED;
-
- vidSetMode(FileMenuMode);
- ++redraw;
- break;
-
- case K_ESCAPE:
- return;
-
- } /* end of switch(key) */
-
- /*
- * update cursor status
- */
- if (cursor_changed)
- {
- /*
- * check row and update column if necessary
- */
- if (cursor.row < 0)
- {
- if (--cursor.col >= 0)
- cursor.row = rows - 1;
- else
- {
- cursor.row = 0;
- cursor.col = 0;
- }
- }
- else if (cursor.row >= rows)
- {
- if (++cursor.col < cols)
- cursor.row = 0;
- else
- {
- cursor.row = rows - 1;
- cursor.col = cols - 1;
- }
- }
-
- /*
- * check column and range limit
- */
- if (cursor.col < 0)
- {
- cursor.col = 0;
- }
- else if (cursor.col >= cols)
- {
- cursor.col = cols - 1;
- }
-
- /*
- * check for empty entries in the last column
- */
- if (cursor.col == last.col && cursor.row > last.row)
- cursor = last;
-
-
- /*
- * check whether a complete redraw is necessary
- */
- if (cursor.col < first.col)
- {
- first.col = cursor.col;
- ++redraw;
- }
- else if (cursor.col >= first.col + display_cols)
- {
- first.col = cursor.col - (display_cols - 1);
- ++redraw;
- }
-
- if (cursor.row < first.row)
- {
- first.row = cursor.row;
- ++redraw;
- }
- else if (cursor.row >= first.row + display_rows)
- {
- first.row = cursor.row - (display_rows - 1);
- ++redraw;
- }
-
- /*
- * update cursor flags
- */
- list_layout[old_cursor.col][old_cursor.row]->flags &= ~CURSOR;
- list_layout[cursor.col][cursor.row]->flags |= CURSOR;
- /*
- * update old and new cursor positions
- * if redraw is TRUE then everything will get redrawn
- */
- if (! redraw)
- {
- int iw, ix, iy;
-
- col = old_cursor.col;
- row = old_cursor.row;
-
- l = list_layout[col][row];
- ix = x + (col - first.col) * col_width;
- iy = y + (row - first.row);
- iw = col_width - 1;
- if (ix + iw > x + width)
- iw = (x + width) - ix;
-
- drawListItem(ix, iy, iw, l);
-
- col = cursor.col;
- row = cursor.row;
-
- l = list_layout[col][row];
- ix = x + (col - first.col) * col_width;
- iy = y + (row - first.row);
- iw = col_width - 1;
- if (ix + iw > x + width)
- iw = (x + width) - ix;
-
- drawListItem(ix, iy, iw, l);
-
- /*
- * update file info
- */
- memset(info_buf, ' ', info_len);
- fileInfo(l->name, info_buf, info_len);
- vidPutText(info.col, info.row, info_buf, info_len,
- LT_CYAN, BLUE);
- }
- }
- } /* end of while (! redraw) */
-
- } /* end of for(;;) */
- }
-
- drawListItem(
- int x,
- int y,
- int w,
- list_t *l
- )
- {
- char buf[256];
- int fg;
- int bg;
-
- memset(buf, ' ', w);
- fg = LT_CYAN;
- bg = BLUE;
-
- if (l != NULL)
- {
- strcpy(buf, l->name);
-
- if (l->flags & SELECTED)
- fg = LT_GREEN;
-
- if (l->flags & CURSOR)
- {
- int tmp;
-
- tmp = fg;
- fg = bg;
- bg = tmp;
- }
- }
- vidPutText(x, y, buf, w, fg, bg);
- }
-